
#ifndef LISTITERATOR_HPP_
#define LISTITERATOR_HPP_

#include "listNode.hpp"

template<class T> class List;

/**
 * Template ListIterator: iterador de la
 * lista de clase List<T>.
 */
template<class T> class ListIterator{
protected:
	List<T> 	*list;
	ListNode<T> *current;

public:

	/**
	 * Constructor de la clase ListIterator<T>.
	 */
	ListIterator(List<T> *l){
		this->list = l;
		this->current = this->list->getFirst();
	}

	/**
	 * Destructor de la clase ListIterator<T>.
	 */
	virtual ~ListIterator(){}

	/**
	 * Chequea si el elemento corriente existe.
	 * @return true si el elemento corriente existe.
	 * @return false en caso contrario.
	 */
	bool hasNext(){
		return (this->current != NULL);
	}

	/**
	 * Devuelve el elemento de clase T alojado en
	 * el corriente, y avanza una posicion.
	 * @return Retorna un puntero al elemento de clase
	 * T alojado en el corriente.
	 */
	T* next(){

		T *datta = this->current->getDatta();
		this->current = this->current->getNext();
		return datta;
	}

	/**
	 * Remueve el elemento corriente devolviendo
	 * el dato que se alojaba en el mismo.
	 * @return Retorna una puntero al elemento de
	 * clase T que se alojaba en el corriente.
	 */
	T* remove(){
		T* datta = this->current->getDatta();
		//delete datta;

		ListNode<T>* nextNode = this->current->getNext();
		ListNode<T>* currTemp = this->current;
		/*
		 * Si el primer nodo es igual al corriente, seteo
		 * como primero de la lista a el siguiente del corriente y
		 * apunto el corriente al primero de la lista
		 */
		if(this->list->getFirst() == this->current){
			this->list->setFirst(nextNode);
			this->current = this->list->getFirst();
		}
		else{
			/*
			 * Me paro en el principio de la lista
			 */
			this->current = this->list->getFirst();
			/*
			 * Itero hasta que el siguiente del corriente sea
			 * igual al elemento que quiero borrar
			 */
			while (this->current->getNext() != currTemp){
				this->current = this->current->getNext();
			}

			this->current->setNext(nextNode);
			this->current = this->current->getNext();
			/*
			 * El que queremos borrar es el currTemp,
			 * el ultimo de la lista queda en this->current,
			 * entonces lo seteamos en la lista como el ultimo
			 */
			if(this->list->getLast() == currTemp)
				this->list->setLast(this->current);
		}
		delete currTemp;
		return datta;
	}

	/**
	 * Agrega un elemento a la lista.
	 * @param datta de clase T*.
	 */
	void add(T* datta){
		ListNode<T>* currTemp = this->current;

		/* Agrega en el medio y al final */
		if(this->list->getFirst()!= currTemp){
			this->current = this->list->getFirst();

			while(this->current->getNext() != currTemp){
				this->current = this->current->getNext();
			}

			/* Inserto el nuevo */
			ListNode<T>* newNode = new ListNode<T>(datta);
			newNode->setNext(currTemp);
			this->current->setNext(newNode);
			this->current = this->current->getNext();
		}
		/* Agrega al principio (lista vacia o no) */
		else if(this->list->getFirst()== currTemp){
			ListNode<T>* newNode = new ListNode<T>(datta);
			newNode->setNext(currTemp);
			this->list->setFirst(newNode);
			this->current=this->list->getFirst();
		}

		while (this->current->getNext() != NULL){
			this->current = this->current->getNext();
		}
		this->list->setLast(this->current);



	}

	/**
	 * Metodo getter del dato de clase T alojado en
	 * el elemento corriente.
	 * @return Retorna un puntero al dato de clase T.
	 */
	T* get(){
		return this->current->getDatta();
	}




};
#endif /* LISTITERATOR_HPP_ */
